package com.jfinal.service;

import com.jfinal.kit.ReflectKit;
import com.jfinal.plugin.activerecord.LogicModel;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.sql.Spec;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.List;

/**
 * 基础服务类
 * <p>
 * Created by Chen on 15/5/25.
 */
public abstract class BaseService<M extends Model> {

    protected M dao;

    @SuppressWarnings ("unchecked")
    public BaseService() {
        Type genericSuperClass = getClass().getGenericSuperclass();

        if (getClass().getName().contains("$$EnhancerByCGLIB$$")) {
            genericSuperClass = getClass().getSuperclass().getGenericSuperclass();
        }

        Type type = ((ParameterizedType) genericSuperClass).getActualTypeArguments()[0];

        try {
            dao = (M) ReflectKit.newInstance(ReflectKit.getClass(type));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public boolean save(M model) {
        if (model.hasColumn("createTime") && model.get("createTime") == null) {
            model.set("createTime", new Date());
        }
        return model.save();
    }

    public boolean delete(M model) {
        if (model.hasColumn(LogicModel.DELETED)) {
            model.set(LogicModel.DELETED, true);
            return model.update();
        }
        return model.delete();
    }

    public boolean update(M model) {
        if (model.hasColumn("updateTime")) {
            model.set("updateTime", new Date());
        }
        return model.update();
    }

    public Model saveAndGet(M model) {
        return model.saveAndGet();
    }

    public Model updateAndGet(M model) {
        return model.updateAndGet();
    }


    public Page<M> paginate(int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) {
        return dao.paginate(pageNumber, pageSize, select, sqlExceptSelect, paras);
    }

    public Page paginate(int pageNumber, int pageSize, boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) {
        return dao.paginate(pageNumber, pageSize, isGroupBySql, select, sqlExceptSelect, paras);
    }

    public Page paginate(int pageNumber, int pageSize, String select, String sqlExceptSelect) {
        return dao.paginate(pageNumber, pageSize, select, sqlExceptSelect);
    }

    public boolean deleteById(Object idValue) {
        return dao.deleteById(idValue);
    }

    public boolean deleteById(Object... idValues) {
        return dao.deleteById(idValues);
    }

    public List find(String sql, Object... paras) {
        return dao.find(sql, paras);
    }

    public List find(String sql) {
        return dao.find(sql);
    }

    public M findFirst(String sql, Object... paras) {
        return (M) dao.findFirst(sql, paras);
    }

    public M findFirst(String sql) {
        return (M) dao.findFirst(sql);
    }

    public M findById(Object idValue) {
        return (M) dao.findById(idValue);
    }

    public M findById(Object... idValues) {
        return (M) dao.findById(idValues);
    }

    public M findByIdLoadColumns(Object idValue, String columns) {
        return (M) dao.findByIdLoadColumns(idValue, columns);
    }

    public M findByIdLoadColumns(Object[] idValues, String columns) {
        return (M) dao.findByIdLoadColumns(idValues, columns);
    }

    public List findByCache(String cacheName, Object key, String sql, Object... paras) {
        return dao.findByCache(cacheName, key, sql, paras);
    }

    public List findByCache(String cacheName, Object key, String sql) {
        return dao.findByCache(cacheName, key, sql);
    }

    public M findFirstByCache(String cacheName, Object key, String sql, Object... paras) {
        return (M) dao.findFirstByCache(cacheName, key, sql, paras);
    }

    public M findFirstByCache(String cacheName, Object key, String sql) {
        return (M) dao.findFirstByCache(cacheName, key, sql);
    }

    public Page paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String select, String sqlExceptSelect, Object... paras) {
        return dao.paginateByCache(cacheName, key, pageNumber, pageSize, select, sqlExceptSelect, paras);
    }

    public Page paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, boolean isGroupBySql, String select, String sqlExceptSelect, Object... paras) {
        return dao.paginateByCache(cacheName, key, pageNumber, pageSize, isGroupBySql, select, sqlExceptSelect, paras);
    }

    public Page paginateByCache(String cacheName, Object key, int pageNumber, int pageSize, String select, String sqlExceptSelect) {
        return dao.paginateByCache(cacheName, key, pageNumber, pageSize, select, sqlExceptSelect);
    }

    public List findBy(Spec spec) {
        return dao.findBy(spec);
    }

    public List findColumnsBy(String columns, Spec spec) {
        return dao.findColumnsBy(columns, spec);
    }

    public M findFirstBy(Spec spec) {
        return (M) dao.findFirstBy(spec);
    }

    public List findAll() {
        return dao.findAll();
    }

    public List findBy(String sqlWhere, Object... paras) {
        return dao.findBy(sqlWhere, paras);
    }

    public List findColumnsBy(String columns, String sqlWhere, Object... paras) {
        return dao.findColumnsBy(columns, sqlWhere, paras);
    }

    public M findFirstBy(String sqlWhere, Object... paras) {
        return (M) dao.findFirstBy(sqlWhere, paras);
    }

    public M findFirstWithCache(String sql, Object... paras) {
        return (M) dao.findFirstWithCache(sql, paras);
    }

    public Page paginate(Spec spec) {
        return dao.paginate(spec);
    }

    public Page paginate(int pageNumber, int pageSize) {
        return dao.paginate(pageNumber, pageSize);
    }

    public Page paginate(int pageNumber, int pageSize, Spec spec) {
        return dao.paginate(spec);
    }

    public boolean existsId(Object id) {
        return dao.existsId(id);
    }

    public boolean exists(String sqlWhere, Object... paras) {
        return dao.exists(sqlWhere, paras);
    }

    public boolean existsBy(Spec spec) {
        return dao.existsBy(spec);
    }

    public Long countBy(Spec spec) {
        return dao.countBy(spec);
    }

    public Long countBy(String sqlWhere, Object... paras) {
        return dao.countBy(sqlWhere, paras);
    }

    public Long countPkBy(String pk, String sqlWhere, Object... paras) {
        return dao.countPkBy(pk, sqlWhere, paras);
    }

    public Integer deleteAll() {
        return dao.deleteAll();
    }

    public Integer deleteBy(String sqlWhere) {
        return dao.deleteBy(sqlWhere);
    }

    public Integer deleteBy(Spec spec) {
        return dao.deleteBy(spec);
    }

    public Integer deleteBy(String sqlWhere, Object... paras) {
        return dao.deleteBy(sqlWhere, paras);
    }

}
